package com.umpay.config;

import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.Role;
import org.springframework.core.Ordered;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
import org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor;
import org.springframework.transaction.interceptor.TransactionInterceptor;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

/**
 * 
 <p>
 * Title:MyBatisConfig
 * </p>
 * <p>
 * Description: 持久层配置类
 * </p>
 * <p>
 * Company: UMPAY
 * </p>
 * 
 * @author lifeng
 * @date 2018年1月17日
 */
@Configuration
@MapperScan(basePackages = "com.umpay.dao")
@PropertySource(value = "classpath:param/jdbc.properties")
// 配置文件路径
public class MyBatisConfig {

	@Autowired
	private Environment env;

	@Bean
	public DataSource onlineDataSource() throws Exception {
		HikariConfig config = new HikariConfig();
		config.setDriverClassName(env
				.getProperty("dataSource.online.driverclass"));
		config.setAutoCommit(false);
		config.setJdbcUrl(env.getProperty("dataSource.online.url"));
		config.setUsername(env.getProperty("dataSource.online.username"));
		config.setPassword(env.getProperty("dataSource.online.password"));
		config.setConnectionTimeout(Long.valueOf(env
				.getProperty("dataSource.online.connectiontimeout")));
		config.setIdleTimeout(Long.valueOf(env
				.getProperty("dataSource.online.idletimeout")));// 一个连接的生命时长（毫秒），超时而且没被使用则被释放（retired），缺省:30分钟，建议设置比数据库超时时长少30秒
		config.setMaximumPoolSize(Long.valueOf(
				env.getProperty("dataSource.online.maxpoolsize")).intValue());
		config.setMaxLifetime(Long.valueOf(env
				.getProperty("dataSource.online.maxlifetime")));// 连接池中允许的最大连接数。缺省值：10；推荐的公式：((core_count
																// * 2) +
																// effective_spindle_count).
																// cpu*2+raid硬盘数
		config.setReadOnly(false);
		config.setMinimumIdle(Integer.valueOf(
				env.getProperty("dataSource.online.minimumidel")).intValue());
		config.addDataSourceProperty("cachePrepStmts", "true");
		config.addDataSourceProperty("prepStmtCacheSize", "250");
		config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
		return new HikariDataSource(config);
	}

//	@Bean
//	public DataSource offlineDataSource() throws Exception {
//		HikariConfig config = new HikariConfig();
//		config.setDriverClassName(env
//				.getProperty("dataSource.online.driverclass"));
//		config.setAutoCommit(true);
//		config.setJdbcUrl(env.getProperty("dataSource.offline.url"));
//		config.setUsername(env.getProperty("dataSource.offline.username"));
//		config.setPassword(env.getProperty("dataSource.offline.password"));
//		config.setConnectionTimeout(Long.valueOf(env
//				.getProperty("dataSource.offline.connectiontimeout")));
//		config.setIdleTimeout(Long.valueOf(env
//				.getProperty("dataSource.offline.idletimeout")));// 一个连接的生命时长（毫秒），超时而且没被使用则被释放（retired），缺省:30分钟，建议设置比数据库超时时长少30秒
//		config.setMaximumPoolSize(Long.valueOf(
//				env.getProperty("dataSource.offline.maxpoolsize")).intValue());
//		config.setMaxLifetime(Long.valueOf(env
//				.getProperty("dataSource.offline.maxlifetime")));// 连接池中允许的最大连接数。缺省值：10；推荐的公式：((core_count
//																	// * 2) +
//																	// effective_spindle_count).
//																	// cpu*2+raid硬盘数
//		config.setReadOnly(true);
//		config.setMinimumIdle(Integer.valueOf(
//				env.getProperty("dataSource.online.minimumidel")).intValue());
//		config.addDataSourceProperty("cachePrepStmts", "true");
//		config.addDataSourceProperty("prepStmtCacheSize", "250");
//		config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
//		return new HikariDataSource(config);
//	}

	@Bean
	@Primary
	public DynamicDataSource dataSource(
			@Qualifier("onlineDataSource") DataSource onlineDataSource) {
		Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
		targetDataSources.put(DatabaseType.onlineDB, onlineDataSource);
//		targetDataSources.put(DatabaseType.offlineDB, offlineDataSource);
		DynamicDataSource dataSource = new DynamicDataSource();
		dataSource.setTargetDataSources(targetDataSources);
		dataSource.setDefaultTargetDataSource(onlineDataSource);
		return dataSource;
	}

	@Bean
	public SqlSessionFactory sqlSessionFactory(
			@Qualifier("onlineDataSource") DataSource onlineDataSource)
			throws Exception {
		SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
		fb.setDataSource(this.dataSource(onlineDataSource));
		fb.setTypeAliasesPackage(env.getProperty("mybatis.typeAliasesPackage"));
		fb.setMapperLocations(new PathMatchingResourcePatternResolver()
				.getResources(env.getProperty("mybatis.mapperLocations")));
		fb.setConfigLocation(new PathMatchingResourcePatternResolver()
				.getResource(env.getProperty("mybatis.config-locations")));
		return fb.getObject();
	}

	/**
	 * 配置事务管理器
	 */
	@Bean(name = "transactionManager")
	public PlatformTransactionManager transactionManager( @Qualifier("onlineDataSource") DataSource onlineDataSource)
			throws Exception {
		return new DataSourceTransactionManager(this.dataSource(onlineDataSource));
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
			@Qualifier("transactionManager") PlatformTransactionManager transactionManager) {
		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		AnnotationTransactionAttributeSource annotationTransactionAttributeSource =  new AnnotationTransactionAttributeSource();
		advisor.setTransactionAttributeSource(annotationTransactionAttributeSource);
		TransactionInterceptor interceptor = new DynamicTransactionInterceptor();
		interceptor.setTransactionAttributeSource(annotationTransactionAttributeSource);
		interceptor.setTransactionManager(transactionManager);
		advisor.setAdvice(interceptor);
		advisor.setOrder(Ordered.LOWEST_PRECEDENCE);
		return advisor;
	}
}
